#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# cron: 30 22 * * *
# new Env("in嘉善任务每日统计")

import os
import re
import glob
import logging
import requests
from datetime import datetime, timedelta
from collections import defaultdict

# 配置日志格式
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)
logger = logging.getLogger("in嘉善Stats")

# ====================== 配置区域 ======================
LOG_DIR_PATTERN = "/ql/data/log/JiaShan*"  # 实际日志目录
TIME_RANGE_HOURS = 24  # 分析最近多少小时的日志
DEBUG_MODE = False      # 设置为True启用详细调试日志
REPORT_FILE = "/ql/data/log/Message/PUSH_in嘉善.log"  # 报告保存路径
# =====================================================

# 在logger定义后设置调试模式
if DEBUG_MODE:
    logger.setLevel(logging.DEBUG)
    logger.debug("调试模式已启用")

def remove_ansi_escape(text):
    """移除ANSI转义序列"""
    ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
    return ansi_escape.sub('', text)

def parse_injia_logs(log_content, account_data, file_path):
    """
    解析in嘉善任务日志内容并提取统计信息 - 适配实际日志格式
    """
    # 编译正则表达式 - 增强匹配规则
    account_section_pattern = re.compile(r'用户：(\d{11})开始任务')
    article_read_pattern = re.compile(r'阅读：请求成功|阅读成功')  # 匹配阅读成功标记
    lottery_count_pattern = re.compile(r'拥有(\d+)次抽奖')
    lottery_result_pattern = re.compile(r'抽奖(?:获得|获得：)([\d.]+)元红包|未中奖-\d+|谢谢参与')
    slider_fail_pattern = re.compile(r'验证失败')
    
    current_account = None
    lines = log_content.split('\n')
    
    for line in lines:
        # 移除ANSI转义序列
        line = remove_ansi_escape(line).strip()
        if not line:
            continue
            
        logger.debug(f"处理行: {line}")
            
        # 检测账号区块开始
        section_match = account_section_pattern.search(line)
        if section_match:
            current_account = section_match.group(1)
            if current_account not in account_data:
                account_data[current_account] = {
                    'articles': 0,
                    'lottery_count': 0,
                    'prizes': [],
                    'slider_fail': 0,
                    'warnings': [],
                    'files': set()  # 记录包含该账号的日志文件
                }
                logger.debug(f"检测到账号区块: {current_account}")
            # 记录日志文件来源
            account_data[current_account]['files'].add(os.path.basename(file_path))
            continue
            
        if not current_account:
            continue
            
        # 统计阅读文章数 - 通过阅读成功标记计数
        if article_read_pattern.search(line):
            account_data[current_account]['articles'] += 1
            logger.debug(f"{current_account} 阅读文章+1")
            continue
            
        # 检测"拥有X次抽奖"行
        lottery_count_match = lottery_count_pattern.search(line)
        if lottery_count_match:
            try:
                count = int(lottery_count_match.group(1))
                # 累加抽奖次数
                account_data[current_account]['lottery_count'] += count
                logger.debug(f"{current_account} 抽奖次数增加: {count}")
            except (AttributeError, ValueError):
                logger.warning(f"无法解析抽奖次数: {line}")
            continue
            
        # 提取抽奖结果
        lottery_result_match = lottery_result_pattern.search(line)
        if lottery_result_match:
            if lottery_result_match.group(1):  # 匹配到红包金额
                amount = float(lottery_result_match.group(1))
                account_data[current_account]['prizes'].append({
                    'type': 'prize',
                    'amount': amount
                })
                logger.debug(f"{current_account} 抽奖获得红包: {amount}元")
            else:  # 匹配到未中奖
                account_data[current_account]['prizes'].append({
                    'type': 'no_prize',
                    'reason': lottery_result_match.group(0)
                })
                logger.debug(f"{current_account} 抽奖结果: {lottery_result_match.group(0)}")
            continue
            
        # 检测滑块验证失败
        if slider_fail_pattern.search(line):
            account_data[current_account]['slider_fail'] += 1
            account_data[current_account]['warnings'].append({
                'type': 'slider_fail',
                'message': '滑块验证失败'
            })
            logger.debug(f"{current_account} 滑块验证失败")
            continue
    
    return account_data

def process_log_directories():
    """
    处理日志目录并解析所有匹配的日志文件
    返回账号统计数据
    """
    # 计算时间范围（最近N小时）
    time_threshold = datetime.now() - timedelta(hours=TIME_RANGE_HOURS)
    logger.info(f"分析时间范围: {time_threshold.strftime('%Y-%m-%d %H:%M:%S')} 至今")
    
    account_data = {}
    processed_files = 0
    skipped_files = 0
    
    # 获取所有匹配的日志文件（按时间倒序）
    all_files = []
    
    # 处理目录模式
    log_dirs = glob.glob(LOG_DIR_PATTERN)
    if not log_dirs:
        logger.warning(f"未找到匹配的日志目录: {LOG_DIR_PATTERN}")
        return account_data
    
    for log_dir in log_dirs:
        if os.path.isdir(log_dir):
            logger.debug(f"扫描目录: {log_dir}")
            for filename in os.listdir(log_dir):
                if filename.endswith('.log'):
                    file_path = os.path.join(log_dir, filename)
                    try:
                        file_mtime = datetime.fromtimestamp(os.path.getmtime(file_path))
                        all_files.append((file_path, file_mtime))
                    except OSError as e:
                        logger.error(f"无法获取文件时间: {file_path} - {str(e)}")
        else:
            # 如果是文件直接添加
            logger.debug(f"添加文件: {log_dir}")
            try:
                file_mtime = datetime.fromtimestamp(os.path.getmtime(log_dir))
                all_files.append((log_dir, file_mtime))
            except OSError as e:
                logger.error(f"无法获取文件时间: {log_dir} - {str(e)}")
    
    if not all_files:
        logger.warning("未找到任何日志文件")
        return account_data
    
    # 按修改时间倒序排序
    all_files.sort(key=lambda x: x[1], reverse=True)
    logger.info(f"找到 {len(all_files)} 个日志文件")
    
    # 处理所有在时间范围内的日志文件
    for file_path, file_mtime in all_files:
        if file_mtime < time_threshold:
            skipped_files += 1
            logger.debug(f"跳过旧文件: {os.path.basename(file_path)} - {file_mtime}")
            continue
            
        try:
            logger.info(f"分析文件: {file_path}")
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
                account_data = parse_injia_logs(content, account_data, file_path)
                processed_files += 1
                    
        except Exception as e:
            logger.error(f"文件解析失败: {file_path} - {str(e)}")
    
    logger.info(f"文件处理完成: 已处理 {processed_files} 个文件, 跳过 {skipped_files} 个")
    return account_data

def generate_table_report(account_data):
    """生成表格格式的统计报告"""
    if not account_data:
        return "⚠️ 未找到有效的账号统计信息", {}
    
    # 计算总计
    totals = {
        'articles': 0,
        'lottery_count': 0,
        'prizes': 0,
        'no_prizes': 0,
        'prize_amount': 0.0,
        'accounts': 0,
        'slider_fails': 0,
        'files_processed': set()
    }
    
    # 构建表格报告
    report_lines = [
        "📊 in嘉善任务每日统计报告",
        "=" * 80,
        "📈 全局汇总:"
    ]
    
    # 添加全局汇总信息
    totals['accounts'] = len(account_data)
    report_lines.append(f"    👥 总账号数: {totals['accounts']}个")
    
    # 计算文章总计
    total_articles = sum(data['articles'] for data in account_data.values())
    totals['articles'] = total_articles
    report_lines.append(f"    📚 总阅读文章数: {total_articles}篇")
    
    # 计算抽奖情况
    total_lottery_count = sum(data.get('lottery_count', 0) for data in account_data.values())
    totals['lottery_count'] = total_lottery_count
    report_lines.append(f"    🎫 总抽奖次数: {total_lottery_count}次")
    
    # 计算中奖情况
    prize_count = 0
    no_prize_count = 0
    prize_amount = 0.0
    
    for data in account_data.values():
        for prize in data.get('prizes', []):
            if prize['type'] == 'prize':
                prize_count += 1
                prize_amount += prize['amount']
            else:
                no_prize_count += 1
                
        totals['slider_fails'] += data.get('slider_fail', 0)
        # 收集处理的文件
        totals['files_processed'].update(data.get('files', []))
    
    totals['prizes'] = prize_count
    totals['no_prizes'] = no_prize_count
    totals['prize_amount'] = prize_amount
    
    win_rate = (prize_count / total_lottery_count * 100) if total_lottery_count > 0 else 0
    
    report_lines.append(f"    🎉 中奖次数: {prize_count}次 (成功率: {win_rate:.2f}%)")
    report_lines.append(f"    💰 红包总金额: {prize_amount:.2f}元")
    report_lines.append(f"    ❌ 未中奖次数: {no_prize_count}次")
    report_lines.append(f"    ⚠️ 滑块验证失败次数: {totals['slider_fails']}次")
    report_lines.append(f"    📁 处理日志文件: {len(totals['files_processed'])}个")
    
    report_lines.append("=" * 80)
    report_lines.append("\n📋 账号详情:")

    # 添加表格标题
    report_lines.append("\n账    号".ljust(20) + "阅读文章".center(10) + "抽奖次数".center(10) + 
                        "中奖情况".center(15) + "红包金额".center(10))
    report_lines.append("─" * 80)
    
    # 添加每个账号的信息
    for account, data in account_data.items():
        # 格式化账号信息
        account_display = f"🔷 {account}" if len(account) < 15 else f"🔷 ...{account[-11:]}"
        
        # 格式化阅读文章
        articles_display = f"📚 {data['articles']}".center(10)
        
        # 格式化抽奖次数
        lottery_count = data.get('lottery_count', 0)
        lottery_display = f"🎫 {lottery_count}".center(10)
        
        # 计算中奖情况
        prize_count = sum(1 for p in data.get('prizes', []) if p['type'] == 'prize')
        no_prize_count = sum(1 for p in data.get('prizes', []) if p['type'] == 'no_prize')
        
        # 格式化中奖情况
        prize_status = f"🎉 {prize_count}次".center(15) if prize_count > 0 else f"❌ {no_prize_count}次".center(15)
        
        # 计算红包金额
        user_prize = sum(p['amount'] for p in data.get('prizes', []) if p['type'] == 'prize')
        prize_display = f"💰 {user_prize:.2f}元".center(10) if user_prize > 0 else "".center(10)
        
        # 添加账号行
        report_lines.append(
            account_display.ljust(20) + 
            articles_display + 
            lottery_display + 
            prize_status + 
            prize_display
        )
        
        # 添加分隔线
        report_lines.append("─" * 80)
    
    # 添加报告时间
    report_lines.append("=" * 80)
    report_lines.append(f"📅 报告生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    
    return "\n".join(report_lines), totals

def push_plus_notify(title, content):
    """
    使用PUSH_PLUS推送通知
    """
    token = os.environ.get('PUSH_PLUS_TOKEN')
    if not token:
        logger.error("未找到PUSH_PLUS_TOKEN环境变量，无法发送通知")
        return False
    
    try:
        # PUSH_PLUS API地址
        url = "http://www.pushplus.plus/send"
        
        # 请求数据
        data = {
            "token": token,
            "title": title,
            "content": content,
            "template": "txt"
        }
        
        # 发送请求
        response = requests.post(url, json=data)
        result = response.json()
        
        if response.status_code == 200 and result.get("code") == 200:
            logger.info("PUSH_PLUS通知发送成功")
            return True
        else:
            logger.error(f"PUSH_PLUS通知发送失败: {result.get('msg', '未知错误')}")
            return False
    except Exception as e:
        logger.error(f"发送PUSH_PLUS通知时出错: {str(e)}")
        return False

def send_notification(title, content):
    """
    发送通知
    """
    # 使用PUSH_PLUS发送通知
    if push_plus_notify(title, content):
        return True
    
    logger.warning("PUSH_PLUS通知发送失败，尝试使用其他通知方式")
    # 这里可以添加其他通知方式，如sendNotify.js
    return False

def main():
    """主函数"""
    task_start = datetime.now()
    logger.info("开始in嘉善任务统计")
    
    try:
        # 步骤1: 处理日志目录
        account_data = process_log_directories()
        
        # 步骤2: 生成报告
        report, totals = generate_table_report(account_data)
        
        # 步骤3: 输出报告
        logger.info("\n" + report)
        
        # 步骤4: 保存报告到文件
        os.makedirs(os.path.dirname(REPORT_FILE), exist_ok=True)
        with open(REPORT_FILE, 'w', encoding='utf-8') as f:
            f.write(report)
        logger.info(f"统计报告已保存至: {REPORT_FILE}")
        
        # 步骤5: 发送通知
        if account_data:
            # 创建通知标题
            title = f"in嘉善任务统计 ({len(account_data)}账号)"
            
            # 创建通知内容
            win_rate = (totals['prizes'] / totals['lottery_count'] * 100) if totals['lottery_count'] > 0 else 0
            notify_content = [
                "📊 in嘉善任务每日统计报告",
                "=" * 40,
                "📈 全局汇总:",
                f"    👥 总账号数: {totals['accounts']}个",
                f"    📚 总阅读文章数: {totals['articles']}篇",
                f"    🎫 总抽奖次数: {totals['lottery_count']}次",
                f"    🎉 中奖次数: {totals['prizes']}次 (成功率: {win_rate:.2f}%)",
                f"    💰 红包总金额: {totals['prize_amount']:.2f}元",
                f"    ❌ 未中奖次数: {totals['no_prizes']}次",
                f"    ⚠️ 滑块验证失败次数: {totals['slider_fails']}次",
                f"    📁 处理日志文件: {len(totals['files_processed'])}个",
                "=" * 40,
                "\n📋 账号详情:"
            ]
            
            # 添加表格标题
            notify_content.append("\n账    号".ljust(20) + "阅读".center(8) + "抽奖".center(8) + 
                                "中奖".center(8) + "金额".center(10))
            notify_content.append("─" * 40)
            
            # 添加每个账号的信息
            for account, data in account_data.items():
                # 格式化账号信息
                account_display = f"🔷 {account}" if len(account) < 15 else f"🔷 ...{account[-11:]}"
                
                # 格式化阅读文章
                articles_display = f"{data['articles']}篇".center(8)
                
                # 格式化抽奖次数
                lottery_count = data.get('lottery_count', 0)
                lottery_display = f"{lottery_count}次".center(8)
                
                # 计算中奖情况
                prize_count = sum(1 for p in data.get('prizes', []) if p['type'] == 'prize')
                prize_status = f"{prize_count}次".center(8)
                
                # 计算红包金额
                user_prize = sum(p['amount'] for p in data.get('prizes', []) if p['type'] == 'prize')
                prize_display = f"{user_prize:.2f}元".center(10) if user_prize > 0 else "-".center(10)
                
                # 添加账号行
                notify_content.append(
                    account_display.ljust(20) + 
                    articles_display + 
                    lottery_display + 
                    prize_status + 
                    prize_display
                )
                
                # 添加分隔线
                notify_content.append("─" * 40)
            
            # 添加报告时间
            notify_content.append("=" * 40)
            notify_content.append(f"📅 报告生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
            
            # 发送通知
            send_notification(title, "\n".join(notify_content))
        else:
            logger.warning("无有效数据，跳过通知发送")
        
        # 计算任务耗时
        task_duration = datetime.now() - task_start
        logger.info(f"任务总耗时: {task_duration.total_seconds():.2f} 秒")
        
        # 返回退出码（0表示成功）
        return 0
    except Exception as e:
        logger.exception(f"任务执行失败: {str(e)}")
        # 发送错误通知
        error_title = "in嘉善任务统计失败"
        error_content = f"任务执行出错: {str(e)}\n\n请查看日志获取详细信息"
        send_notification(error_title, error_content)
        return 1

if __name__ == "__main__":
    import sys
    import requests
    
    # 设置时区为北京时间
    os.environ['TZ'] = 'Asia/Shanghai'
    
    exit_code = main()
    sys.exit(exit_code)